package list;

import iterator.MeuListIterator;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class MeuArrayList<E> implements List<E> {

	int size;

	// Não dá pra fazer E[] porque não é possível instanciar fazendo new E[]
	Object[] elementos;

	static Integer CAPACIDADE_INICIAL = 10;

	public MeuArrayList() {
		this(CAPACIDADE_INICIAL);
	}

	public MeuArrayList(int tamanho) {
		this.size = 0;
		this.elementos = new Object[tamanho];
	}

	@Override
	public boolean add(E e) {
		if (this.size == this.elementos.length) {
			System.out.println("Redimensionando.");

			// aumentar o tamanho
			// copia os elementos que tinham e insere null nas novas posições
			int tamanhoNovo = this.elementos.length * 2;

			Object[] novo = new Object[tamanhoNovo];

			int i;
			for (i = 0; i < this.elementos.length; i++) {
				novo[i] = this.elementos[i];
			}

			for (; i < tamanhoNovo; i++) {
				novo[i] = null;
			}

			this.elementos = novo;
		}

		this.elementos[size] = e;
		size++;

		return true;
	}

	@Override
	public void add(int index, E element) {
		validaIndice(index);

		if (this.size == this.elementos.length) {
			// aumentar o tamanho
			// copia os elementos que tinham e insere null nas novas posições
			int tamanhoNovo = this.elementos.length * 2;

			Object[] novo = new Object[tamanhoNovo];

			int i;
			for (i = 0; i < index; i++) {
				novo[i] = this.elementos[i];
			}

			novo[i] = element;

			int j;
			for (j = i + 1; j < this.elementos.length; j++) {
				novo[j] = this.elementos[j];
			}
			
			for (i = j; i < tamanhoNovo; i++) {
				novo[i] = null;
			}
		}

		for (int i = size; i > index; i--) {
			elementos[i] = elementos[i - 1];
		}

		elementos[index] = element;
		size++;

	}

	@Override
	public boolean remove(Object o) {
		for (int i = 0; i < this.size; i++) {
			Object elemento = this.elementos[i];

			if (elemento.equals(o)) {
				// copiar todo mundo que tá na frente pra trás
				int j = i;
				for (; j < this.size - 1; j++) {
					this.elementos[j] = this.elementos[j + 1];
				}

				this.elementos[j] = null;
				this.size--;

				return true;
			}
		}
		return false;
	}

	@Override
	public E remove(int index) {
		validaIndice(index);

		E elementoRemovido = (E) this.elementos[index];

		for (int i = index; i < this.size - 1; i++) {
			this.elementos[i] = this.elementos[i + 1];
		}
		// faltou colocar null na ultima posicao
		this.size--;

		return elementoRemovido;
	}

	@Override
	public int indexOf(Object o) {
		for (int i = 0; i < this.size; i++) {
			Object elemento = this.elementos[i];

			if (elemento.equals(o)) {
				return i;
			}
		}
		return -1;
	}

	@Override
	public E get(int index) {
		validaIndice(index);

		return (E) this.elementos[index];
	}

	private void validaIndice(int index) {
		if (index > this.size - 1) {
			throw new ArrayIndexOutOfBoundsException("Posição não existe!!");
		}
	}

	@Override
	public E set(int index, E element) {
		validaIndice(index);

		E elementoAntigo = (E) this.elementos[index];
		this.elementos[index] = element;

		return elementoAntigo;
	}

	@Override
	public int size() {
		return size;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	@Override
	public boolean contains(Object o) {
		for (int i = 0; i < size; i++) {
			Object elemento = elementos[i];

			if (elemento.equals(o)) {
				return true;
			}
		}

		return false;
	}

	@Override
	public Iterator<E> iterator() {
		return new MeuListIterator(this, this.size);
	}

	@Override
	public Object[] toArray() {
		return Arrays.copyOf(this.elementos, this.elementos.length);
	}

	@Override
	public <T> T[] toArray(T[] a) {
		a = (T[]) Arrays.copyOf(this.elementos, this.elementos.length);
		return a;
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		for (Object object : c) {
			if (!contains(object)) {
				return false;
			}
		}

		return true;
	}

	@Override
	public boolean addAll(Collection<? extends E> c) {

		if (c.size() == 0) {
			return false;
		}

		for (E e : c) {
			add(e);
		}

		return true;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder("[");

		for (int i = 0; i < this.size; i++) {
			Object e = this.elementos[i];
			builder.append(e.toString() + ", ");
		}

		return builder.append("]").toString();
	}

	@Override
	public boolean addAll(int index, Collection<? extends E> c) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void clear() {
		this.elementos = new Object[CAPACIDADE_INICIAL];
		this.size = 0;
	}

	@Override
	public int lastIndexOf(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public ListIterator<E> listIterator() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ListIterator<E> listIterator(int index) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<E> subList(int fromIndex, int toIndex) {
		// TODO Auto-generated method stub
		return null;
	}

}
